package jhunter.rt.conf;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

import jhunter.common.exception.ConfigException;
import jhunter.rt.conf.ext.ActionExt;

public class Node {

	private String id;

	public Node(String id) {
		super();
		this.id = id;
	}

	private Object object;

	private Node parent;

	private ConfType confType;

	private String uriPath;

	private String file;

//	private List<Node> children = new NodeList();
	private List<Node> children = new CopyOnWriteArrayList<Node>();

	private Map<String, Node> childrenMap = new ConcurrentHashMap<String, Node>();

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public Object getObject() {
		return object;
	}

	public void setObject(Object object) {
		this.object = object;
	}

	public Node getParent() {
		return parent;
	}

	public void setParent(Node parent) {
		this.parent = parent;
	}

	public List<Node> getChildren() {
		return children;
	}

	public void setChildren(List<Node> children) {
		this.children = children;
	}

	public ConfType getConfType() {
		return confType;
	}

	public void setConfType(ConfType confType) {
		this.confType = confType;
	}

	public Map<String, Node> getChildrenMap() {
		return Collections.unmodifiableMap(childrenMap);
	}

	public String getUriPath() {
		return uriPath;
	}

	/**
	 * Type = action, module, app 时有值
	 * 
	 * @return
	 */
	public String getFullUriPath() {
		List<String> path = new ArrayList<String>();
		Node start = this;
		while (start.getParent() != null) {
			path.add(start.getUriPath());
			start = start.getParent();
		}
		StringBuilder sb = new StringBuilder();
		for (int i = path.size() - 1; i >= 0; i--) {
			String p = path.get(i);
			if (p == null || p.trim().length() == 0) {
				continue;
			}
			if (!p.startsWith("/") && !sb.toString().endsWith("/")) {
				sb.append("/");
			}
			sb.append(path.get(i));
		}
		return sb.toString();
	}

	public PathInfo getPathInfo() {
		if(getObject() instanceof ActionExt) {
			ActionExt action = (ActionExt) this.getObject();
			return new PathInfo(getFullUriPath(), HttpMethod.getByString(action.getAction().getHttpMethod()));	
		}
		throw new ConfigException("Not Suport!!!");
	}

	public void setUriPath(String uriPath) {
		this.uriPath = uriPath;
	}

	protected class NodeList extends CopyOnWriteArrayList<Node> {

		private static final long serialVersionUID = -364319001170223897L;

		@Override
		public Node set(int index, Node element) {
			childrenMap.put(element.getId(), element);
			return super.set(index, element);
		}

		@Override
		public boolean add(Node e) {
			childrenMap.put(e.getId(), e);
			return super.add(e);
		}

		@Override
		public void add(int index, Node element) {
			childrenMap.put(element.getId(), element);
			super.add(index, element);
		}

		@Override
		public Node remove(int index) {
			childrenMap.remove(this.get(index).getId());
			return super.remove(index);
		}

		@Override
		public boolean remove(Object o) {
			childrenMap.remove(((Node) o).getId());
			return super.remove(o);
		}

		@Override
		public boolean addIfAbsent(Node e) {
			childrenMap.put(e.getId(), e);
			return super.addIfAbsent(e);
		}

		@Override
		public boolean removeAll(Collection<?> c) {
			if (c != null) {
				for (Object object : c) {
					childrenMap.remove(((Node) object).getId());
				}
			}
			return super.removeAll(c);
		}

		@Override
		public int addAllAbsent(Collection<? extends Node> c) {
			if (c != null) {
				for (Object object : c) {
					childrenMap.put(((Node) object).getId(), (Node) object);
				}
			}
			return super.addAllAbsent(c);
		}

		@Override
		public void clear() {
			childrenMap.clear();
			super.clear();
		}

		@Override
		public boolean addAll(Collection<? extends Node> c) {
			if (c != null) {
				for (Object object : c) {
					childrenMap.put(((Node) object).getId(), (Node) object);
				}
			}
			return super.addAll(c);
		}

		@Override
		public boolean addAll(int index, Collection<? extends Node> c) {
			if (c != null) {
				for (Object object : c) {
					childrenMap.put(((Node) object).getId(), (Node) object);
				}
			}
			return super.addAll(index, c);
		}

	}

	public String getFile() {
		return file;
	}

	public void setFile(String file) {
		this.file = file;
	}

}
